/**
 * 
 */
package myth.cc.file;

import java.util.ArrayList;
import java.util.List;

import myth.cc.bean.Label;
import myth.cc.bean.Label.LabelType;

class StateSet {
	int sourceLink;
	int targetLink;
	
	int sourceLineLink;
	int targetLineLink;
	
	int sourceLineNum;
	int targetLineNum;
	
	int targetState;
	int sourceState;
		
	public StateSet() {
		targetLink=sourceLink=sourceLineNum
		=targetLineNum=sourceLineLink=targetLineLink=0;
		targetState=sourceState=256;
	}
}

/**
 * @author Lv Cheng
 *
 */
public class FileComparer {
	public static int STATE_IN_LABEL_BODY=1;
	public static int STATE_IN_CODE=2;
	public static int STATE_ADD=4;
	public static int STATE_DELETE=8;
	public static int STATE_ENDED=16;
	public static int STATE_IN_LABEL_HEAD=32;
	public static int STATE_IS_COMMAND=64;
	public static int STATE_BEGIN=128;
	public static int STATE_GETNEXTLINE=256;
	public static int STATE_ISLOC=512;
	public static int STATE_ADD_LABEL_BEGIN=1024;
	public static int STATE_DELETE_LABEL_BEGIN=2048;
	
	private String getNextLine(String s,StateSet ss,int filetype) {
		StringBuffer tmp=new StringBuffer(0);
//		int llink=0;
		if (filetype == 0) { // souceFile
			ss.sourceLineLink = ss.sourceLink;
			while (true) {
				ss.sourceLink++;
				if (ss.sourceLink >= s.length()
						|| s.charAt(ss.sourceLink) == '\n') {
					if (ss.sourceLink>s.length())
						ss.sourceLink = s.length();
					break;
				}
				tmp.append(s.charAt(ss.sourceLink));
			}
			if (ss.sourceLink == s.length())
				ss.sourceState |= FileComparer.STATE_ENDED;
		}
		else {			// target File
			ss.targetLineLink=ss.targetLink;
			while (true) {
				ss.targetLink++;
				if (ss.targetLink >= s.length()
						|| s.charAt(ss.targetLink) == '\n') {
					if (ss.targetLink>s.length())
						ss.targetLink=s.length();
					break;
				}
				tmp.append(s.charAt(ss.targetLink));
			}
			if (ss.targetLink==s.length()) 
				ss.targetState|=FileComparer.STATE_ENDED;
		}
		return tmp.toString();
	}
	
	private boolean isLetter(char c) {
		return ((c>='a' && c<='z')
				|| (c>='A' && c<='Z')
				|| (c>='0' && c<='9') || c=='}');
	}
	
	private String getNextParam(String s,StateSet ss,int fileType) {
		StringBuffer tmp=new StringBuffer(0);
		if (fileType==0) {
			boolean isBegin=true;
			while (true) {
				ss.sourceLineLink++;
				if (ss.sourceLineLink==ss.sourceLink
						|| (!isLetter(s.charAt(ss.sourceLineLink))&&!isBegin)) break;
				if (!isLetter(s.charAt(ss.sourceLineLink))) continue;
				isBegin=false;
				tmp.append(s.charAt(ss.sourceLineLink));
			}
		}
		else {
			boolean isBegin=true;
			while (true) {
				ss.targetLineLink++;
				if (ss.targetLineLink==ss.targetLink
						|| (!isLetter(s.charAt(ss.targetLineLink))&&!isBegin)) break;
				if (!isLetter(s.charAt(ss.targetLineLink))) continue;
				isBegin=false;
				tmp.append(s.charAt(ss.targetLineLink));
			}
		}
		return tmp.toString();
	}
	
	private String getNextParam(String s,StateSet ss) {
		StringBuffer tmp=new StringBuffer(0);
		boolean isBegin=true;
		for (int i=0;i<s.length();i++){
			if (!isLetter(s.charAt(i))&&!isBegin) break;
			if (!isLetter(s.charAt(i))) continue;
			isBegin=false;
			tmp.append(s.charAt(i));
		}
		return tmp.toString();
	}
	private void getState(String s,StateSet ss,int fileType) {
		if (fileType==0) {
//			if (s.length()==0) ss.sourceState|=FileComparer.STATE_ENDED;
			for (int i=1;i<s.length();i++) {
				if (s.charAt(i)=='{') ss.sourceState|=FileComparer.STATE_IN_CODE;
				if (s.charAt(i)=='/' && s.charAt(i-1)=='/') {
					if ((ss.sourceState&FileComparer.STATE_ISLOC)==1) {
						// Do nothing
					}
					else {
						return;
					}
				}
				if (isLetter(s.charAt(i))
						&& (ss.sourceState&FileComparer.STATE_IN_LABEL_BODY)==0) {
					ss.sourceState|=FileComparer.STATE_ISLOC;
				}
				if (s.charAt(i)=='*' && s.charAt(i-1)=='/') {
					ss.sourceState|=FileComparer.STATE_IN_LABEL_BODY;
				}
				if (s.charAt(i)=='/' && s.charAt(i-1)=='*') {
					ss.sourceState&=~FileComparer.STATE_IN_LABEL_BODY;
				}
			}
		}
		else {
			for (int i=1;i<s.length();i++) {
				if (s.charAt(i)=='{') ss.targetState|=FileComparer.STATE_IN_CODE;
				if (s.charAt(i)=='/' && s.charAt(i-1)=='/') {
					if ((ss.targetState&FileComparer.STATE_ISLOC)==1) {
						// Do nothing
					}
					else {
						return;
					}
				}
				if (isLetter(s.charAt(i))
						&& (ss.targetState&FileComparer.STATE_IN_LABEL_BODY)==0) {
					ss.targetState|=FileComparer.STATE_ISLOC;
				}
				if (s.charAt(i)=='*' && s.charAt(i-1)=='/') {
					ss.targetState|=FileComparer.STATE_IN_LABEL_BODY;
				}
				if (s.charAt(i)=='/' && s.charAt(i-1)=='*') {
					ss.targetState&=~FileComparer.STATE_IN_LABEL_BODY;
				}
				if (s.charAt(i)=='@' && 
						(ss.targetState&FileComparer.STATE_IN_LABEL_BODY)==1) {
					ss.targetLineLink=i;
					String word=getNextParam(s,ss);
					if (word.compareToIgnoreCase("add")==0) {
						ss.targetState|=FileComparer.STATE_ADD;
						ss.targetState|=FileComparer.STATE_ADD_LABEL_BEGIN;
					}
					if (word.compareToIgnoreCase("delete")==0) {
						ss.targetState|=FileComparer.STATE_DELETE_LABEL_BEGIN;
						ss.targetState|=FileComparer.STATE_DELETE;
					}
				}
			}
		}
	}
	
	public List<Label> comparerFile(String sourceFile,
			String targetFile) {
		List<Label> label=new ArrayList<Label>();
		StateSet ss=new StateSet();
		String sourceLine="";
		String targetLine="";
		StringBuffer labelBuffer=new StringBuffer();
		Label tmp=null;
//		System.out.println((256&256))
		while (true) {
//			Get one line from source file,and update source state
//			Get one line from target file,and update target state
//			System.out.println(ss.sourceState);
			if ((ss.sourceState&FileComparer.STATE_GETNEXTLINE)==FileComparer.STATE_GETNEXTLINE) {
				sourceLine=getNextLine(sourceFile,ss,0);
				getState(sourceLine,ss,0);
				if ((ss.sourceState&FileComparer.STATE_ISLOC)==FileComparer.STATE_ISLOC) 
					ss.sourceLineNum++;
			}
//			System.out.println("111");
			if ((ss.targetState&FileComparer.STATE_GETNEXTLINE)==FileComparer.STATE_GETNEXTLINE) {
				targetLine=getNextLine(targetFile,ss,1);
				getState(targetLine,ss,1);
				if ((ss.targetState&FileComparer.STATE_ISLOC)==FileComparer.STATE_ISLOC) 
					ss.targetLineNum++;
			}
			
			ss.sourceState&=~FileComparer.STATE_GETNEXTLINE;
			ss.targetState&=~FileComparer.STATE_GETNEXTLINE;
			
//			if ((ss.sourceState&FileComparer.STATE_ISLOC)==FileComparer.STATE_ISLOC)
//				ss.sourceState|=FileComparer.STATE_GETNEXTLINE;
//			if ((ss.targetState&FileComparer.STATE_ISLOC)==FileComparer.STATE_ISLOC)
//				ss.targetState|=FileComparer.STATE_GETNEXTLINE;
//			System.out.println(targetLine+"  "+sourceLine+ "  "+targetLine.compareTo(sourceLine));
			if (targetLine.compareTo(sourceLine)==0) {
				ss.sourceState|=FileComparer.STATE_GETNEXTLINE;
				ss.targetState|=FileComparer.STATE_GETNEXTLINE;
				if ((ss.targetState&FileComparer.STATE_ADD)==FileComparer.STATE_ADD) {
					tmp.setEndLine(ss.targetLineNum);
					label.add(tmp);
				}			
				if ((ss.targetState&FileComparer.STATE_DELETE)==FileComparer.STATE_DELETE) {
					tmp.setEndLine(ss.sourceLineNum);
					label.add(tmp);
				}
				ss.targetState&=~FileComparer.STATE_ADD;
				ss.targetState&=~FileComparer.STATE_DELETE;
			}
			else
			{
//				System.out.println("NOT equal");
			}
			
			/*if ((ss.targetState&FileComparer.STATE_IN_LABEL_HEAD)==1) {
//				Analyse the label in the head
//				Write the content to label arrayList
			}
			*/
			if ((ss.targetState&FileComparer.STATE_ADD)==FileComparer.STATE_ADD) {
				if ((ss.targetState&FileComparer.STATE_IN_LABEL_BODY)==FileComparer.STATE_IN_LABEL_BODY) {
					ss.targetState|=FileComparer.STATE_GETNEXTLINE;
					if ((ss.targetState&FileComparer.STATE_ADD_LABEL_BEGIN)==FileComparer.STATE_ADD_LABEL_BEGIN)
					{
						tmp=new Label();
						tmp.setType(LabelType.Add);
						labelBuffer=new StringBuffer();
						labelBuffer.append(targetLine);
						ss.targetState&=~FileComparer.STATE_ADD_LABEL_BEGIN;
					}
					else
						labelBuffer.append(targetLine);
					
					/*String word=getNextParam(targetLine,ss,1);
					if (word.length()==0) {
						tmp=new Label();
						tmp.setType(LabelType.Add);
					}
					if (word.compareToIgnoreCase("author")==0) {
						StringBuffer author=new StringBuffer();
						while (true) {
							word=getNextParam(targetLine,ss,1);
							if (word.length()==0) break;
							author.append(word);
						}
						tmp.setAuthor(author.toString());
					}
					if (word.compareToIgnoreCase("Date") == 0) {
						Date date = new Date();
						word = getNextParam(targetLine, ss, 1);
						date.setYear(Integer.parseInt(word) - 1900);
						word = getNextParam(targetLine, ss, 1);
						date.setMonth(Integer.parseInt(word));
						word = getNextParam(targetLine, ss, 1);
						date.setHours(Integer.parseInt(word));
						tmp.setDate(date);
					}
					if (word.compareToIgnoreCase("reason") == 0) {
						StringBuffer reason = new StringBuffer();
						while (true) {
							word = getNextParam(targetLine, ss, 1);
							if (word.length() == 0)
								break;
							reason.append(word).append(' ');
						}
						tmp.setReason(reason.toString());
					}*/
				}
				else {
					labelBuffer.append(targetLine);
					ss.targetState|=FileComparer.STATE_GETNEXTLINE;
					if ((ss.targetState&FileComparer.STATE_IN_LABEL_BODY)==0) {
						if (tmp.getBeginLine()==0) {
//							 ���Label���ݵĽ���
							System.out.println(labelBuffer.toString());
							tmp.setBeginLine(ss.targetLineNum+1);
						}
					}
				}	
			}
			
			if ((ss.targetState&FileComparer.STATE_DELETE)==FileComparer.STATE_DELETE) {
				if ((ss.targetState&FileComparer.STATE_IN_LABEL_BODY)==FileComparer.STATE_IN_LABEL_BODY) {
					ss.targetState|=FileComparer.STATE_GETNEXTLINE;
					if ((ss.targetState&FileComparer.STATE_DELETE_LABEL_BEGIN)==FileComparer.STATE_DELETE_LABEL_BEGIN) {
						tmp=new Label();
						tmp.setType(LabelType.Delete);
						labelBuffer=new StringBuffer();
						labelBuffer.append(targetLine).append('\n');
						ss.targetState&=~FileComparer.STATE_DELETE_LABEL_BEGIN;
						ss.sourceState|=FileComparer.STATE_DELETE_LABEL_BEGIN;
					}
					else {
						labelBuffer.append(targetLine);
					}
					/*String word=getNextParam(targetLine,ss,1);
					if (word.length()==0) {
						tmp=new Label();
						tmp.setType(LabelType.Delete);
					}
					if (word.compareToIgnoreCase("author")==0) {
						StringBuffer author=new StringBuffer();
						while (true) {
							word=getNextParam(targetLine,ss,1);
							if (word.length()==0) break;
							author.append(word);
						}
						tmp.setAuthor(author.toString());
					}
					if (word.compareToIgnoreCase("Date") == 0) {
						Date date = new Date();
						word = getNextParam(targetLine, ss, 1);
						date.setYear(Integer.parseInt(word) - 1900);
						word = getNextParam(targetLine, ss, 1);
						date.setMonth(Integer.parseInt(word));
						word = getNextParam(targetLine, ss, 1);
						date.setHours(Integer.parseInt(word));
						tmp.setDate(date);
					}
					if (word.compareToIgnoreCase("reason") == 0) {
						StringBuffer reason = new StringBuffer();
						while (true) {
							word = getNextParam(targetLine, ss, 1);
							if (word.length() == 0)
								break;
							reason.append(word).append(' ');
						}
						tmp.setReason(reason.toString());
					}*/
				}
				else {
					labelBuffer.append(targetLine);
					ss.sourceState|=FileComparer.STATE_GETNEXTLINE;
					if ((ss.sourceState&FileComparer.STATE_DELETE_LABEL_BEGIN)==FileComparer.STATE_DELETE_LABEL_BEGIN) { 
						ss.targetState|=FileComparer.STATE_GETNEXTLINE;
						ss.sourceState&=~FileComparer.STATE_DELETE_LABEL_BEGIN;
					}
					if ((ss.sourceState&FileComparer.STATE_IN_LABEL_BODY)==0) {
						if (tmp.getBeginLine()==0) {
							// ���Label���ݵĽ���
							System.out.println(labelBuffer.toString());
							tmp.setBeginLine(ss.sourceLineNum+1);
						}
					}
				}
			}
			if ((ss.targetState&FileComparer.STATE_ENDED)==FileComparer.STATE_ENDED) break;
			if ((ss.sourceState&FileComparer.STATE_ENDED)==FileComparer.STATE_ENDED)
				ss.targetState|=FileComparer.STATE_GETNEXTLINE;
			ss.sourceState&=~FileComparer.STATE_ISLOC;
			ss.targetState&=~FileComparer.STATE_ISLOC;
		}
		System.out.println(label.get(0).getBeginLine()+" "+label.get(0).getEndLine());
		return label;
	}
}


